﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindGoes6.Sys
{
    /// <summary>
    /// 此类基于System.Process提供了多种方式用于简化DOS程序的调用。
    /// </summary>
    public class ConsoleInvoker
    {
        /// <summary>
        /// 用于执行DOS自带的命令并返回执行结果（仅包括执行结果信息）。
        /// 由于DOS执行几乎不会卡死，所以没有设置等待时间。
        /// 调用格式如： RunDosCommand("dir", "*.exe);
        /// </summary>
        /// <param name="doscmd">待调用的DOS命令。</param>
        /// <param name="arguments">参数列表</param>
        /// <returns></returns>
        public static string RunDosCommand(string doscmd, params string[] arguments)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = "/C " + doscmd + " " + string.Join(" ", arguments);
            p.StartInfo.UseShellExecute = false; // 不显示用户界面
            p.StartInfo.RedirectStandardOutput = true; // 是否重
            p.StartInfo.CreateNoWindow = true;
            // 返回数据
            string output = "";
            try
            {
                if (p.Start())//开始进程  
                {
                    p.WaitForExit(); //等待进程结束，等待时间为指定的毫秒  
                    output = p.StandardOutput.ReadToEnd();//读取进程的输出  
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);//捕获异常，输出异常信息
            }
            finally
            {
                if (p != null)
                    p.Close();
            }

            return output;
        }

        /// <summary>
        /// 用于执行第三方程序，并返回执行结果。
        /// </summary>
        /// <param name="execuable">可执行的程序。</param>
        /// <param name="timeout">超时时间，单位秒，设置为0时不限时。</param>
        /// <param name="arguments">可执行程序的参数列表。</param>
        /// <returns></returns>
        public static string RunCommand(string execuable, int timeout, params string[] arguments)
        {
            Process p = new Process();
            p.StartInfo.FileName = Path.GetFullPath(execuable);
            p.StartInfo.Arguments = string.Join(" ", arguments);
            p.StartInfo.UseShellExecute = false; // 不显示用户界面
            p.StartInfo.RedirectStandardOutput = true; // 是否重定位输出于当前输出。
            p.StartInfo.CreateNoWindow = true; // 不创建新窗口。

            string output = "";
            try
            {
                if (p.Start())//开始进程  
                {
                    if (timeout == 0)
                    {
                        p.WaitForExit();//这里无限等待进程结束  
                    }
                    else
                    {
                        p.WaitForExit(timeout * 1000); //等待进程结束，等待时间为指定的毫秒  
                    }

                    // 如果还没有结束，就将线程关闭
                    if (!p.HasExited)
                        p.Kill();

                    output = p.StandardOutput.ReadToEnd();//读取进程的输出  
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);//捕获异常，输出异常信息
            }
            finally
            {
                if (p != null)
                    p.Close();
            }

            return output;
        }

        public static string RunCommand(string execuable, string arguments, int timeout = 0)
        {
            Process p = new Process();
            p.StartInfo.FileName = Path.GetFullPath(execuable);
            p.StartInfo.Arguments = arguments;
            p.StartInfo.UseShellExecute = false; // 不显示用户界面
            p.StartInfo.RedirectStandardOutput = true; // 是否重定位输出于当前输出。
            p.StartInfo.CreateNoWindow = true; // 不创建新窗口。

            string output = "False";
            try
            {
                if (p.Start())//开始进程  
                {
                    DateTime dt1 = DateTime.Now;
                    if (timeout == 0)
                    {
                        p.WaitForExit();//这里无限等待进程结束  
                    }
                    else
                    {
                        p.WaitForExit(timeout * 1000); //等待进程结束，等待时间为指定的毫秒  
                    }

                    DateTime dt2 = DateTime.Now;

                    Console.WriteLine($"Being waited for {(dt2 - dt1).TotalMilliseconds}");
                    // 如果还没有结束，就将线程关闭
                    if (!p.HasExited)
                        p.Kill();

                    output = p.StandardOutput.ReadToEnd();//读取进程的输出  
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);//捕获异常，输出异常信息
            }
            finally
            {
                if (p != null)
                    p.Close();
            }

            return output;
        }



        /// <summary>
        /// 向指定的程序注入需要执行的程序。
        /// </summary>
        /// <param name="execuable"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public static string RunCommands(string execuable, params string[] cmds)
        {
            Process p = new Process();
            p.StartInfo.FileName = execuable;
            p.StartInfo.Arguments = string.Join(" ", cmds);
            p.StartInfo.UseShellExecute = false; // 不显示用户界面
            p.StartInfo.RedirectStandardOutput = true; // 是否重定位输出于当前输出。
            p.StartInfo.CreateNoWindow = true; // 不创建新窗口。
            p.StartInfo.RedirectStandardInput = true;

            string output = "";
            try
            {
                if (p.Start())//开始进程  
                {
                    for (int i = 0; i < cmds.Length; i++)
                    {
                        p.StandardInput.WriteLine(cmds[i]);
                        Console.WriteLine(p.StandardOutput.ReadToEnd());
                    }

                    p.StandardInput.WriteLine("exit");
                    output = p.StandardOutput.ReadToEnd();//读取进程的输出  
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);//捕获异常，输出异常信息
            }
            finally
            {
                if (p != null)
                    p.Close();
            }

            return output;
        }


    }
}
